import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter_webrtc/flutter_webrtc.dart';
import 'package:freedom/entity/restful.dart';
import 'package:freedom/page/mahjong/common/message_content.dart';
import 'package:freedom/util/api_router.dart';
import 'package:freedom/util/http.dart';
import 'package:synchronized/synchronized.dart';

class UserPeerConnection {
  late int userId;
  MediaStream? localMediaStream;
  MediaStream? remoteMediaStream;
  var senders = <RTCRtpSender>[];
  bool openMirco = false;
  // 是否连接成功
  bool conn = false;
  static final Lock _lock = Lock();

  final Map<String, dynamic> configuration = {
    'bundlePolicy': "max-bundle",
    'rtcpMuxPolicy': "require",
    'iceTransportPolicy': "all",
    'iceServers': [
      {
        "urls": [
          "turn:xplay3000.cn:30010?transport=udp",
          "turn:xplay3000.cn:30010?transport=tcp"
        ],
        "username": "PZf1xI2vDb4CXx68",
        "credential": "PsyqPyoMmUDJ89fZp3ghdFwlR6lyLH0l"
      },
      {
        "urls": ["stun:xplay3000.cn:30010"]
      }
    ]
  };

  final Map<String, dynamic> constraints = {
    'audio': {
      'echoCancellation': true,
      'autoGainControl': true,
      'googNoiseSuppression': true,
      'googHighpassFilter': true,
      'noiseSuppression': true,
    },
    'video': false,
    /* 'audio': {
        'echoCancellation': true,
        'autoGainControl': true,
      },
      'video': {
        'width': 300,
        'height': 300,
        'frameRate': 30,
      },*/
    'mandatory': {
      'OfferToReceiveAudio': true,
      'OfferToReceiveVideo': false,
    },
    'optional': [],
  };
  final RTCVideoRenderer remoteRenderer = RTCVideoRenderer();
  RTCPeerConnection? pc;
  UserPeerConnection(this.userId, this.localMediaStream, this.openMirco);
  Future<RTCPeerConnection> _createPeerConnnection(
      MediaStream? localMediaStream) async {
    return _lock.synchronized(() async {
      if (pc != null) {
        return pc!;
      }
      senders = [];
      pc = await createPeerConnection(configuration, constraints);
      pc!.onIceCandidate = (event) {
        if (event.candidate != null) {
          // 向服务器发送我加入进来了 服务器收到后发送给其它人 不包含自己
          var data = MessageContent<Map>(type: MessageContent.MT_VOICE, body: {
            'cmd': "candidate",
            'msg': {
              'sdpMLineIndex': event.sdpMLineIndex,
              'sdpMid': event.sdpMid,
              'candidate': event.candidate
            },
            'remoteUid': userId
          }).toJson();
          Http.getInstance().request<Restful>(ApiRouter.roomMessage,
              contentType: ContentType.json,
              type: RequestEnum.POST,
              showErrorMsg: true,
              data: data,
              success: (data) {});
        }
      };
      pc!.onTrack = (event) async {
        if (event.track.kind == 'audio') {
          remoteMediaStream = event.streams[0];
          await remoteRenderer.initialize();
          remoteRenderer.srcObject = event.streams[0];
        }
      };
      pc!.onConnectionState = (event) {
        switch (event) {
          case RTCPeerConnectionState.RTCPeerConnectionStateClosed:
            pc?.dispose();
            pc = null;
            conn = false;
            break;
          case RTCPeerConnectionState.RTCPeerConnectionStateFailed:
            conn = false;
            break;
          case RTCPeerConnectionState.RTCPeerConnectionStateDisconnected:
          case RTCPeerConnectionState.RTCPeerConnectionStateNew:
          case RTCPeerConnectionState.RTCPeerConnectionStateConnecting:
            break;
          case RTCPeerConnectionState.RTCPeerConnectionStateConnected:
            // 连接成功
            conn = true;
            break;
        }
      };
      pc!.onSignalingState = (state) {
        switch (state) {
          case RTCSignalingState.RTCSignalingStateStable:
          case RTCSignalingState.RTCSignalingStateHaveLocalOffer:
          case RTCSignalingState.RTCSignalingStateHaveRemoteOffer:
          case RTCSignalingState.RTCSignalingStateHaveLocalPrAnswer:
          case RTCSignalingState.RTCSignalingStateHaveRemotePrAnswer:
          case RTCSignalingState.RTCSignalingStateClosed:
            break;
        }
      };
      pc!.onIceConnectionState = (event) {
        if (kDebugMode) {
          print("onIceConnectionState:${event.name}");
        }
      };
      // 暂时屏蔽掉添加 tracks 是不是应该在打开麦克风的时候添加
      localMediaStream?.getTracks().forEach((track) async {
        var sender = await pc!.addTrack(track, localMediaStream);
        senders.add(sender);
      });
      return pc!;
    });
  }

  // 将本地的  track 移除掉
  void clearTrack() {
    if (senders.isNotEmpty) {
      for (var sender in senders) {
        pc?.removeTrack(sender);
      }
    }
    senders = [];
  }

  /// 收到别人的offer
  void remoteOffer(Map content) async {
    if (pc == null) {
      await _createPeerConnnection(localMediaStream);
    }
    //  pc?.restartIce();
    RTCSessionDescription session =
        RTCSessionDescription(content["sdp"], content["type"]);
    pc!.setRemoteDescription(session).whenComplete(() async {
      doAnswer();
    });
  }

  /// 自己的offer发送给别人
  void doOffer({bool openMirco = false}) async {
    if (pc == null) {
      await _createPeerConnnection(localMediaStream);
    }
    // 这里的session 会话就是offer通信信令需要转发给每个客户端
    // 拿到过后的数据 永远都是发送给其它人
    await pc?.createOffer(constraints).then((os) {
      pc?.setLocalDescription(os).whenComplete(() {
        // 向服务器发送我加入进来了 服务器收到后发送给其它人 不包含自己
        var data = MessageContent<Map>(
                type: MessageContent.MT_VOICE,
                body: {'cmd': "offer", 'msg': os.toMap(), 'remoteUid': userId})
            .toJson();
        Http.getInstance().request<Restful>(ApiRouter.roomMessage,
            contentType: ContentType.json,
            type: RequestEnum.POST,
            showErrorMsg: true,
            data: data,
            success: (data) {});
      });
    });
  }

  void doAnswer() async {
    if (pc == null) {
      await _createPeerConnnection(localMediaStream);
    }
    // 这里的session 会话就是answer需要转发给每个客户端
    await pc!.createAnswer(constraints).then((as) {
      pc!.setLocalDescription(as).whenComplete(() {
        var data = MessageContent<Map>(
                type: MessageContent.MT_VOICE,
                body: {'cmd': "answer", 'msg': as.toMap(), 'remoteUid': userId})
            .toJson();
        Http.getInstance().request<Restful>(ApiRouter.roomMessage,
            contentType: ContentType.json,
            type: RequestEnum.POST,
            showErrorMsg: true,
            data: data,
            success: (data) {});
      });
    });
  }

  /// 收到别人的Answer
  void remoteAnswer(Map content) async {
    if (pc == null) {
      await _createPeerConnnection(localMediaStream);
    }
    await pc!.setRemoteDescription(
        RTCSessionDescription(content["sdp"], content["type"]));
  }

  void remoteCandidate(Map content) async {
    if (pc == null) {
      return;
      //await _createPeerConnnection(localMediaStream);
    }
    var candidate = RTCIceCandidate(
      content['candidate'],
      content['sdpMid'],
      content['sdpMLineIndex'],
    );
    pc!.addCandidate(candidate);
  }

  void resetState(MediaStream? mediaStream) async {
    // 如果之前本地已经创建了 跟 B对象的连接   又没有开启  语音 那么这个localMediaStream 可能为空

    if (mediaStream != null && localMediaStream == null) {
      localMediaStream = mediaStream;
      if (pc == null) {
        await _createPeerConnnection(localMediaStream);
      }
      clearTrack();
      localMediaStream?.getTracks().forEach((track) async {
        var sender = await pc!.addTrack(track, localMediaStream!);
        senders.add(sender);
      });
    }
  }

  void logout() {
    clearTrack();
    localMediaStream = null;
    pc?.dispose();
    remoteRenderer.dispose();
  }
}
